package com.sx.core.utils;

import com.alibaba.fastjson.JSON;
import com.sx.core.vo.Params;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.ByteArrayBody;
import org.apache.http.entity.mime.content.InputStreamBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.ssl.TrustStrategy;
import org.apache.http.util.CharsetUtils;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.SSLContext;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URL;
import java.net.URLEncoder;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by lihao on 2017/7/20.
 */
public class HttpClientInstance {
    /*
    最大连接数
     */
    static int maxTotal = 200;
    /*
    设置每个主机的并发数
     */
    static int defaultMaxPerRoute = 50;
    /*
    多少时间去检查可用的链接
     */
    static int validateAfterInactivity = 3600;

    /*
    创建连接的最长时间
     */
    static int connectTimeout = 5000;

    /*
    从连接池中获取到连接的最长时间
     */
    static int connectionRequestTimeout = 500;

    /*
    数据传输的最长时间
     */
    static int socketTimeout = 30000;



    static PoolingHttpClientConnectionManager cm = null;
    /*
    HttpClient对象的构建器
     */
    static HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
    /*
    请求配置的构建器
     */
    static RequestConfig.Builder builder = RequestConfig.custom();
    static RequestConfig requestConfig = null;

    static CloseableHttpClient httpclient = null;

    private Log log = LogFactory.getLog(getClass());

    private volatile static HttpClientInstance instance = null;


    public static interface HttpStreamCallback{
        <T> T callback(InputStream inputStream);
    }

    private HttpClientInstance() {
    }


    public static HttpClientInstance getInstance() {
        if (instance == null) {
            synchronized (HttpClientInstance.class) {
                if (instance == null) {
                    instance = new HttpClientInstance();
                    instance.init();
                }
            }
        }
        return instance;
    }

    private void init() {



        SSLContext sslContext = null;
        try {
            sslContext = new SSLContextBuilder().loadTrustMaterial(null,
                    TrustSelfSignedStrategy.INSTANCE).build();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        } catch (KeyStoreException e) {
            e.printStackTrace();
        }
        SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(
                sslContext, NoopHostnameVerifier.INSTANCE);

        httpClientBuilder.setSSLSocketFactory(sslSocketFactory).setSSLHostnameVerifier( NoopHostnameVerifier.INSTANCE);
        Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
                .register("http", new PlainConnectionSocketFactory())
                .register("https", sslSocketFactory)
                .build();
        cm = new PoolingHttpClientConnectionManager(registry);
        cm.setMaxTotal(maxTotal);
        cm.setDefaultMaxPerRoute(defaultMaxPerRoute);
        cm.setValidateAfterInactivity(validateAfterInactivity);
        httpClientBuilder.setConnectionManager(cm);

        builder.setConnectTimeout(connectTimeout);
        builder.setConnectionRequestTimeout(connectionRequestTimeout);
        builder.setSocketTimeout(socketTimeout);
        requestConfig = builder.build();
        httpclient=httpClientBuilder.build();


    }
    public CloseableHttpClient getHttpclient(){
        return httpclient;
    }
    public static SSLConnectionSocketFactory createSSLFactory() {
        try {
            SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(
                    null, new TrustStrategy() {
                        // 信任所有
                        public boolean isTrusted(X509Certificate[] chain,
                                                 String authType) throws CertificateException {
                            return true;
                        }
                    }).build();
            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext);
            return  sslsf;
        } catch (KeyManagementException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyStoreException e) {
            e.printStackTrace();
        }
        return null;
    }

    public String get(String url) {
        CloseableHttpResponse response = null;
        try {
            // 创建http GET请求
            HttpGet httpGet = new HttpGet(url);
            httpGet.setConfig(this.requestConfig);

            // 执行请求
            response = httpclient.execute(httpGet);
            // 判断返回状态是否为200
            log.debug("response status>>>>>"+response.getStatusLine().getStatusCode());
            return EntityUtils.toString(response.getEntity(), "UTF-8");
        } catch (Exception e) {
            log.error("get["+url+"]>>>>");
            log.error("get", e);
        } finally {
            if (response != null) {
                try {
                    response.close();
                } catch (IOException e) {
                }
            }
        }
        return null;
    }
    public <T> T getStream(String url,HttpStreamCallback callback) {
        CloseableHttpResponse response = null;
        InputStream instream=null;
        try {
            // 创建http GET请求
            HttpGet httpGet = new HttpGet(url);
            httpGet.setConfig(this.requestConfig);

            // 执行请求
            response = httpclient.execute(httpGet);
            // 判断返回状态是否为200
            log.debug("response status>>>>>"+response.getStatusLine().getStatusCode());
            HttpEntity entity = response.getEntity();
            if(entity!=null){
                instream = entity.getContent();
            }
            return callback.callback(instream);
        } catch (Exception e) {
            log.error("getStream", e);
        } finally {
            if (response != null) {
                try {
                    response.close();
                } catch (IOException e) {
                }
            }
            IOUtils.closeQuietly(instream);
        }
        return null;
    }

    public String get(String url,Map<String,String> header) {
        CloseableHttpResponse response = null;
        try {
            // 创建http GET请求
            HttpGet httpGet = new HttpGet(url);
            httpGet.setConfig(this.requestConfig);
            if (header != null) {
                Set<String> keys = header.keySet();
                for (Iterator<String> i = keys.iterator(); i.hasNext();) {
                    String key = (String) i.next();
                    httpGet.addHeader(key, header.get(key));
                }
            }
            // 执行请求
            response = httpclient.execute(httpGet);
            // 判断返回状态是否为200
            log.debug("response status>>>>>"+response.getStatusLine().getStatusCode());
            return EntityUtils.toString(response.getEntity(), "UTF-8");
        } catch (Exception e) {
            log.error("get["+url+"]>>>>");
            log.error("get", e);
        } finally {
            if (response != null) {
                try {
                    response.close();
                } catch (IOException e) {
                }
            }
        }
        return null;
    }


    public String post(String url, Map<String, String> params) {
        HttpPost httpPost = new HttpPost(url);
        CloseableHttpResponse response = null;
        String str=null;
        try {
            if (null != params) {
                ArrayList<NameValuePair> pairs = new ArrayList<NameValuePair>();
                for (Map.Entry<String, String> entry : params.entrySet()) {
                    pairs.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
                }
                // 构造一个form表单式的实体
                UrlEncodedFormEntity entity = new UrlEncodedFormEntity(pairs);
                // 将请求实体设置到httpPost对象中
                httpPost.setEntity(entity);
            }

            httpPost.setConfig(this.requestConfig);
            // 伪装成浏览器
            httpPost.setHeader("User-Agent",
                    "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.94 Safari/537.36");
            // 执行请求
            response = httpclient.execute(httpPost);
            log.debug("response status>>>>>"+response.getStatusLine().getStatusCode());
            return EntityUtils.toString(response.getEntity(), "UTF-8");
        } catch (Exception e) {
            log.error("post["+url+"]>>>>"+ JSON.toJSONString(params));
            log.error("reps["+url+"]>>>>"+str);
            log.error("post", e);
        } finally {
            if (response != null) {
                try {
                    response.close();
                } catch (IOException e) {
                }
            }
        }
        return null;
    }
    public String postJson(String url, Object jsonObje) {
        ;
        CloseableHttpResponse response = null;
        String code=null;
        try {
            URL url1 = new URL(url);
            URI uri = new URI(url1.getProtocol(), url1.getHost(), url1.getPath(), url1.getQuery(), null);
            // 创建http POST请求
            HttpPost httpPost = new HttpPost(uri);
            httpPost.setConfig(this.requestConfig);
            String str=null;
            String req=null;

            if (jsonObje != null) {
        //            ByteArrayEntity byteArrayEntity=new ByteArrayEntity(JSON.toJSONBytes(jsonObje),ContentType.APPLICATION_JSON);
                // 构造一个form表单式的实体
                req= JSON.toJSONString(jsonObje);
                StringEntity stringEntity = new StringEntity(req, ContentType.APPLICATION_JSON);
                // 将请求实体设置到httpPost对象中
                httpPost.setEntity(stringEntity);
            }

            code=getString(req);
            log.debug("req["+code+"]>>>>>"+req);



            response = httpclient.execute(httpPost);
            log.debug("response status>>>>>"+response.getStatusLine().getStatusCode());
            return EntityUtils.toString(response.getEntity(), "UTF-8");
        }catch (Exception e){
            log.error("post json",e);
        } finally {
            if (response != null) {
                try {
                    response.close();
                } catch (IOException e) {
                }
            }
            long end=System.currentTimeMillis();
        }
        return null;
    }
    public String postString(String url, String params){
        CloseableHttpResponse response=null;
        String str=null;
        try {
            HttpPost httpost = new HttpPost(url);
            httpost.setConfig(requestConfig);
            if(params!=null){
                ByteArrayEntity pentity = null;
                pentity = new ByteArrayEntity(params.getBytes("UTF-8"));
                httpost.setEntity(pentity);
            }

            response = httpclient.execute(httpost);
            log.debug("response status>>>>>"+response.getStatusLine().getStatusCode());
            return EntityUtils.toString(response.getEntity(), "UTF-8");
        }catch (Exception e){
            log.error("post["+url+"]>>>>"+params);
            log.error("resp["+url+"]>>>>"+str);
            log.error("postString",e);
        }finally {
            if(response!=null){
                try {
                    response.close();
                } catch (IOException e) {
                }
            }
        }
        return null;
    }


    public String postJsonThrows(String url, Object jsonObje) throws  Exception {
        long start=System.currentTimeMillis();
        // 创建http POST请求
        HttpPost httpPost = new HttpPost(url);
        httpPost.setConfig(this.requestConfig);
        String str=null;
        String req=null;

        if (jsonObje != null) {
//            ByteArrayEntity byteArrayEntity=new ByteArrayEntity(JSON.toJSONBytes(jsonObje),ContentType.APPLICATION_JSON);
            // 构造一个form表单式的实体
            req= JSON.toJSONString(jsonObje);
            StringEntity stringEntity = new StringEntity(req, ContentType.APPLICATION_JSON);
            // 将请求实体设置到httpPost对象中
            httpPost.setEntity(stringEntity);
        }

        String code=getString(req);
        log.debug("req["+code+"]>>>>>"+req);

        CloseableHttpResponse response = null;
        try {
            response = httpclient.execute(httpPost);
            log.debug("response status>>>>>"+response.getStatusLine().getStatusCode());
            return EntityUtils.toString(response.getEntity(), "UTF-8");
        }catch (Exception e){
            log.error("post["+code+"]>>>>"+ JSON.toJSONString(jsonObje));
            log.error("resp["+code+"]>>>>"+str);
            log.error("post json",e);
            throw  e;
        } finally {
            if (response != null) {
                try {
                    response.close();
                } catch (IOException e) {
                }
            }
            long end=System.currentTimeMillis();
            log.debug("耗时["+url+"]>>>>"+(end-start)/1000+"秒");
        }
    }


    public String postFile(String url,String filename,File file,Map<String,Object> params){
        try {
            return postFile(url,filename,FileUtils.openInputStream(file),params);
        } catch (IOException e) {
            log.error("upload file error",e);
        }
        return null;
    }
    public static void main(String[] args) throws Exception{
        String str=HttpClientInstance.getInstance().postFile("http://localhost:8011/upload","XYCQ1521176207_26774.jpg",FileUtils.openInputStream(new File("/Users/lihao/Downloads/XYCQ1521176207_26774.jpg")),new Params().p("path","test2009/kkk.jpg"));
        System.out.println(str);
    }
     public String postFile(String url,String filename,InputStream inputStream,Map<String,Object> params){
        CloseableHttpResponse response=null;
        String str=null;
        try {
            HttpPost httpost = new HttpPost(url);
            httpost.setConfig(requestConfig);

            MultipartEntityBuilder multipartEntityBuilder=MultipartEntityBuilder.create();
            multipartEntityBuilder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
            if(params!=null){
                for(Map.Entry<String,Object> entry:params.entrySet()){
                    multipartEntityBuilder.addTextBody(entry.getKey(), entry.getValue().toString(), ContentType.TEXT_PLAIN.withCharset("UTF-8"));
                }
            }
            InputStreamBody bin = new InputStreamBody(inputStream,filename);
            multipartEntityBuilder.addPart("file",bin).setCharset(CharsetUtils.get("UTF-8"));
            httpost.setEntity(multipartEntityBuilder.build());
            response = httpclient.execute(httpost);
            log.debug("response status>>>>>"+response.getStatusLine().getStatusCode());
            return EntityUtils.toString(response.getEntity(), "UTF-8");
        }catch (Exception e){
            log.error("post["+url+"]>>>>"+params);
            log.error("resp["+url+"]>>>>"+str);
            log.error("postString",e);
        }finally {
            if(response!=null){
                try {
                    response.close();
                } catch (IOException e) {
                }
            }
        }
        return null;
    }
    public String postFile(String url,String filename,byte[] bytes,Map<String,Object> params){
        CloseableHttpResponse response=null;
        String str=null;
        try {
            HttpPost httpost = new HttpPost(url);
            httpost.setConfig(requestConfig);

            MultipartEntityBuilder multipartEntityBuilder=MultipartEntityBuilder.create();
            multipartEntityBuilder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
            if(params!=null){
                for(Map.Entry<String,Object> entry:params.entrySet()){
                    multipartEntityBuilder.addTextBody(entry.getKey(), entry.getValue().toString(), ContentType.TEXT_PLAIN.withCharset("UTF-8"));
                }
            }
            ByteArrayBody bin = new ByteArrayBody(bytes,filename);
            multipartEntityBuilder.addPart("file",bin).setCharset(CharsetUtils.get("UTF-8"));
            httpost.setEntity(multipartEntityBuilder.build());
            response = httpclient.execute(httpost);
            log.debug("response status>>>>>"+response.getStatusLine().getStatusCode());
            return EntityUtils.toString(response.getEntity(), "UTF-8");
        }catch (Exception e){
            log.error("post["+url+"]>>>>"+params);
            log.error("resp["+url+"]>>>>"+str);
            log.error("postString",e);
        }finally {
            if(response!=null){
                try {
                    response.close();
                } catch (IOException e) {
                }
            }
        }
        return null;
    }


    public String sslPost(String url ,String params,String pass,String p12_file){
        CloseableHttpResponse response=null;
        InputStream inputStream=null;
        try{
            KeyStore keyStore  = KeyStore.getInstance("PKCS12");
            inputStream =new FileInputStream(new File(p12_file)) ;
//            InputStream inputStream =new FileInputStream(System.getProperty("apiclient_cert")) ;
            keyStore.load(inputStream, pass.toCharArray());

            // Trust own CA and all self-signed certs
            SSLContext sslcontext = SSLContexts.custom()
                    .loadKeyMaterial(keyStore, pass.toCharArray())
                    .build();
            // Allow TLSv1 protocol only
            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                    sslcontext,
                    new String[] { "TLSv1" },
                    null,
                    SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
            CloseableHttpClient httpclient = HttpClients.custom()
                    .setSSLSocketFactory(sslsf)
                    .build();

            HttpPost httpost = new HttpPost(url);
            httpost.setConfig(requestConfig);

            ByteArrayEntity pentity = new ByteArrayEntity(params.getBytes("UTF-8"));
            httpost.setEntity(pentity);
            response = httpclient.execute(httpost);
            if (response.getStatusLine().getStatusCode() == 200) {
                String xml=EntityUtils.toString(response.getEntity(), "UTF-8");
                if(log.isInfoEnabled()){
                    log.info("sslPost:--"+xml);
                }
                return xml;
            }

        }catch (Exception e){
            log.error("sslPost error",e);
        }finally {
            try {
                if(response!=null){
                    response.close();
                }
                if(inputStream!=null){
                    inputStream.close();
                }
            } catch (IOException e) {
            }

        }
        return null;
    }
    private static String getString(String str){
        Pattern p = Pattern.compile(",\"Code\":\"(.*?)\"");
        Matcher m = p.matcher(str);
        ArrayList<String> strs = new ArrayList<String>();
        while (m.find()) {
            return m.group(1);
        }
        return "";
    }
    private static String convertUrl(String url){
        try {
            return URLEncoder.encode(url, "UTF-8").replace("+", "%20");
        } catch (UnsupportedEncodingException e) {
        }
        return null;
    }



}
